#include "Parser.h"

#define NUMARGS 5

using namespace glm;
using namespace std;

int crash = 0;
int SHADING = 0;
int REFLECT = 6;
int ALIAS = 3;

void debug() {
    printf("segfault %d\n", crash++);
}

/* for rotating the camera */
mat4 lookTowards(vec3 up, vec3 lookAt, vec3 location) {
    /* centers our coordinates around location */
    vec3 loc = lookAt - location;
    vec3 axis = cross(up, loc);
    mat4 ret = mat4(1.f);
    /* how much to rotate around the Y-axis */
    /* I set it to 0 here because it turned out to be wrong when it wasn't 0 */
    float rotY = (loc.z == 0.0 && loc.x == 0.0) || 1 ? 0.0 :
    atan2(loc.x, loc.z) * 180.0/3.1415926 -90.0;
    float rotA = 90 - asin(length(axis)/length(loc)) * 180.0 / 3.1415926;

    if (loc.y > 0) {
        rotA = -rotA;
    }

    ret = rotate(ret, rotA, axis);
    ret = rotate(ret, rotY, up);
    return ret;
}

class Raytracer {
public: 
    Scene *scene;
    string output;
    Image *image;
    float width, height;
    gNode *planes;
    AABB *headBox;

    Raytracer(int w, int h, string file, Scene *s) {
        Geometry *g;
        AABB *b;
        bNode *boxes;
        int numBoxes = 0;

        boxes = NULL;
        planes = NULL;

        scene = s;
        image = new Image(w, h);
        output = file;
        width = w;
        height = h;

        scene->geometry.reset();
        while (scene->geometry.hasNext()) {
            g = scene->geometry.getNext();
            if (g->type() == T_PLANE) {
                planes = new gNode(planes, (WPlane *) g);
            }
            else if (g->type() == T_CONE) {
            }
            else {
                b = g->generateAABB();
                //g->print();
                //b->print();
                if (b) {
                    boxes = new bNode(boxes, b);
                }
                numBoxes++;
            }
        }

        headBox = generateBoxes(boxes, 0, numBoxes);
    }

    Geometry *intersectBoxes(AABB *b, Ray *r) {
        static int printNum = 0;
        Geometry *g1, *g2;
        if (b->intersect(r)) {
            if (b->isLeaf) {
                if (b->g->intersect(r)) {
                    return b->g;
                }
                
                return NULL;
            }
            else {
                g1 = intersectBoxes(b->left, r);
                g2 = intersectBoxes(b->right, r);

                if (g2) {
                    return g2;
                } 

                return g1;
            }
        }

/*        b->print();
        printf("Ray:\tpoint: <%.3f, %.3f, %.3f>\tdir <%.3f, %.3f, %.3f>\n",
                r->point.x, r->point.y, r->point.z, r->d.x, r->d.y, r->d.z);
*/
        return NULL;
    }

    Geometry *intersectScene(Ray *r) {
        Geometry *ret = NULL;
        gNode *temp;
        
        /*scene->geometry.reset();
        while(scene->geometry.hasNext()) {
            temp = scene->geometry.getNext();
            if (temp->intersect(r)) {
                ret = temp;
            }
        }*/
        ret = intersectBoxes(headBox, r);

        temp = planes;
        while (temp != NULL) {
            if (temp->plane->intersect(r)) {
                ret = temp->plane;
            }

            temp = temp->next;
        }

        return ret;
    }

    color_t shadePhong(Geometry *g, WLight *l, Ray *r);
    color_t shadeGaussian(Geometry *g, WLight *l, Ray *r);
    color_t shadeBeckmann(Geometry *g, WLight *l, Ray *r);
    color_t shadeCookTorrance(Geometry *g, WLight *l, Ray *r);

    color_t normalShading(Geometry *g, Ray *r, int ref);
    color_t refractiveShading(Geometry *g, Ray *r, int ref);

    color_t lightRay(Geometry *g, Ray *r, int ref) {
        color_t clr;
        /* beer's law attenuation */
        float atten;
        float dDotd;

        clr.r = 0.0;
        clr.g = 0.0;
        clr.b = 0.0;
        clr.f = 0.0;
        if (!g) {
            return clr;
        }
        
        if (g->finish.refraction == 0.0) {
            clr = normalShading(g, r, ref);

            /*clr.r += g->pigment.r * g->finish.ambient;
            clr.g += g->pigment.g * g->finish.ambient;
            clr.b += g->pigment.b * g->finish.ambient;*/
        }
        else {
            clr = refractiveShading(g, r, ref);

            /* this ray is entering the material */
            if (dot(-r->d, g->getNormal(r)) < 0) {
                atten = exp(-r->t * g->finish.ambient * (g->pigment.r));
                clr.r = clr.r * atten /*+ 
                    g->pigment.r * g->finish.ambient * atten*/;

                atten = exp(-r->t * g->finish.ambient * (g->pigment.g));
                clr.g = clr.g * atten /*+ 
                    g->pigment.g * g->finish.ambient * atten*/;

                atten = exp(-r->t * 0.15 * (g->pigment.b));
                clr.b = clr.b * atten /*+ 
                    g->pigment.b * g->finish.ambient * atten*/;
            }
        }

        clr.f = g->pigment.f;
        return clr;
    }

    vec2 jitter(float min, float max) {
        float q;
        vec2 ret;

        q = ((float) rand()) / RAND_MAX;
        ret.x = min - (min - max) * q;
        q = ((float) rand()) / RAND_MAX;
        ret.y = min - (min - max) * q;

        return ret;
    }

    void trace() {
        Ray r;
        Geometry *g;
        WLight *l;
        color_t clr, clr_write;
        int i, j, index;
        float delta, x, y;
        float max;
        float percent = 0.0;
        mat4 lookat;
        vec3 t, u, v, w;
        vec4 tPrime;
        float right = length(scene->camera->right) / 2.0;
        float left = -right;;
        float top = length(scene->camera->up) / 2.0;
        float bot = -top;
        vec2 prev, next;
        vec2 middle;
        clock_t start, cur;
        double diff;

        start = clock();

        lookat = lookTowards(scene->camera->up, scene->camera->lookAt,
                scene->camera->location);
        delta = 1.0 / ALIAS;

        u = normalize(scene->camera->right);
        v = normalize(scene->camera->up);
        w = cross(u, v);

        diff = 0.0;
        
        cout << endl;
        for (i = 0; i < width; i++) {
            for (j = 0; j < height; j++) {
                clr_write.r = 0.0;
                clr_write.g = 0.0;
                clr_write.b = 0.0;
                clr_write.f = 0.0;
 
                for (index = 0; index < ALIAS * ALIAS; index++) {
                    x = index % ALIAS;
                    y = index / ALIAS;
                    prev = vec2(x * delta, y * delta);
                    next = vec2(x * delta + delta, y * delta + delta);
                    middle = (prev + next) / 2.0f;
                    middle += jitter(-delta / 3.0, delta / 3.0);

                    r.point = scene->camera->location;
                    t = r.point + 
                        (left + (right - left) *
                         ((float) i + middle.x) / width) * u +
                        (bot + (top - bot) * 
                         ((float) j + middle.y) / height) * v +
                        -1.0f * w;

                    t = normalize(t - scene->camera->location);
                    tPrime = lookat * vec4(t.x, t.y, t.z, 0.0);
                    t = vec3(tPrime.x, tPrime.y, tPrime.z);

                    r.d = t;
                    r.t = FLT_MAX;

                    g = intersectScene(&r);
                    clr.r = 0.0;
                    clr.g = 0.0;
                    clr.b = 0.0;
                    clr.f = 0.0;
                    
                    if (g) {
                        clr = lightRay(g, &r, REFLECT);
                    }

                    max = std::max(std::max(clr.r, clr.g), clr.b);
                    if (max > 1.0) {
                        clr.r /= max;
                        clr.g /= max;
                        clr.b /= max;
                    }

                    clr_write.r += clr.r;
                    clr_write.g += clr.g;
                    clr_write.b += clr.b;
                    cur = clock();
                    if (isatty(1) && 
                            (double) (cur - start) > CLOCKS_PER_SEC / 33.5) {
                        diff += ((double) (cur - start))/CLOCKS_PER_SEC;
                        start = clock();
                        percent = (i * height + j + ((float)index) / 
                                ALIAS * ALIAS) / height / width;
                        printf("Time elapsed: %.2fs\tComplete: %05.2f%%\t\t"
                                "Estimated time remaining: %.2fs\r",
                                diff, percent * 100.0f, diff / percent - diff);
                    }
                }

               clr_write.r /= ALIAS * ALIAS;
                clr_write.g /= ALIAS * ALIAS;
                clr_write.b /= ALIAS * ALIAS;

                image->pixel(i, j, clr_write);
            }
        }

        diff += ((double) (cur - start)) / CLOCKS_PER_SEC;
        printf("Time elapsed: %.2fs\tComplete: %%100.00\n", diff);
        image->WriteTga((char *)output.c_str());
    }
};

color_t Raytracer::normalShading(Geometry *g, Ray *r, int ref) {
    Ray *rShadow, *rBounce;
    Geometry *gShadow, *gBounce;
    WLight *l;
    color_t clr, clr1, clr2;
    vec3 normal;
    float dDotn;
    
    clr.r = 0.0;
    clr.g = 0.0;
    clr.b = 0.0;
    clr.f = 0.0;

    clr1.r = 0.0;
    clr1.g = 0.0;
    clr1.b = 0.0;
    clr1.f = 0.0;

    clr2.r = 0.0;
    clr2.g = 0.0;
    clr2.b = 0.0;
    clr2.f = 0.0;

    normal = g->getNormal(r);
    rShadow = new Ray();
    scene->lights.reset();
    int count = 0;
    while (scene->lights.hasNext()) {
        l = scene->lights.getNext();

        rShadow->point = r->point + r->t * r->d;
        rShadow->d = 
            normalize(l->location - rShadow->point);
        /* prevent self shadowing */
        rShadow->point += normal * 0.001f + rShadow->d * 0.001f;
        rShadow->t = FLT_MAX;

        gShadow = intersectScene(rShadow);
        
        if (!gShadow || gShadow->type() == T_PLANE) {
            if (SHADING == 0) {
                clr = shadePhong(g, l, r);
            }
            else if (SHADING == 1) {
                clr = shadeGaussian(g, l, r);
            }
            else if (SHADING == 2) {
                clr = shadeBeckmann(g, l, r);
            }
            else if (SHADING == 3) {
                clr = shadeCookTorrance(g, l, r);
            }

            clr1.r += clr.r;
            clr1.g += clr.g;
            clr1.b += clr.b;

        }
        else if (gShadow->finish.refraction != 0.0) {
            clr1.r += 
                g->pigment.r * g->finish.diffuse * g->finish.ambient * 0.2;
            clr1.g += 
                g->pigment.g * g->finish.diffuse * g->finish.ambient * 0.2;
            clr1.b += 
                g->pigment.b * g->finish.diffuse * g->finish.ambient * 0.2;
        }
    }
    delete rShadow;

    normal = g->getNormal(r);
    dDotn = dot(-r->d, normal);
    if (g->finish.reflection && ref) {
        if (dDotn < 0) {
            normal = -normal;
            dDotn = dot(-r->d, normal);
        }

        rBounce = new Ray();
        rBounce->d = normalize(r->d +
                2.0f * dDotn * normal);
        rBounce->t = FLT_MAX;
        /* move bounce off of the geometry a little */
        rBounce->point = r->point + r->t * r->d +
            normal * 0.01f;

        gBounce = intersectScene(rBounce);
        if (gBounce) {
            clr2 = lightRay(gBounce, rBounce, ref - 1);
        }
        delete rBounce;
    }

    clr.r = clr1.r + clr2.r * g->finish.reflection;
    clr.g = clr1.g + clr2.g * g->finish.reflection;
    clr.b = clr1.b + clr2.b * g->finish.reflection;
    clr.f = 0.0;

    clr.r += g->pigment.r * g->finish.ambient;
    clr.g += g->pigment.g * g->finish.ambient;
    clr.b += g->pigment.b * g->finish.ambient;


    return clr;
}

color_t Raytracer::refractiveShading(Geometry *g, Ray *r, int ref) {
    Ray *rShadow, *rBounce, *rRefract;
    Geometry *gShadow, *gBounce, *gRefract;
    WLight *l;
    color_t clr, clr1, clr2, clr3;
    vec3 normal;
    float deter, fresnel = 1.0;
    float n1, n2;
    float dDotn, R0;


    clr.r = 0.0;
    clr.g = 0.0;
    clr.b = 0.0;
    clr.f = 0.0;

    clr1.r = 0.0;
    clr1.g = 0.0;
    clr1.b = 0.0;
    clr1.f = 0.0;

    clr2.r = 0.0;
    clr2.g = 0.0;
    clr2.b = 0.0;
    clr2.f = 0.0;

    clr3.r = 0.0;
    clr3.g = 0.0;
    clr3.b = 0.0;
    clr3.f = 0.0;

    normal = g->getNormal(r);
    dDotn = dot(-r->d, normal);
    /* we're exiting the object */
    if (dDotn < 0) {
        n1 = g->finish.ior;
        n2 = 1.0;
        normal = -normal;
        dDotn = dot(-r->d, normal);
    }
    else {
        n1 = 1.0;
        n2 = g->finish.ior;
    }

    if (ref) {
        rBounce = new Ray();
        rBounce->d = normalize(r->d +
                2.0f * dDotn * normal);
        rBounce->t = FLT_MAX;
        rBounce->point = r->point + r->t * r->d +
                normal * 0.01f;

        gBounce = intersectScene(rBounce);
        if (gBounce) {
            clr1 = lightRay(gBounce, rBounce, ref - 1);
        }

        delete rBounce;

        R0 = (n1 - n2) * (n1 - n2) / ((n1 + n2) * (n1 + n2));
        fresnel = R0 + (1.0f - R0) * (1.0f - 
                dDotn * dDotn);
        deter = 1.0f - (n1 * n1)/(n2 * n2) * (1.0f - 
                dDotn * dDotn * dDotn * dDotn * dDotn);
        /* total internal reflection */
        if (deter < 0.f) {
            fresnel = 1.0;
        }
        else {
            rRefract = new Ray();
            rRefract->d = normalize(-n1/n2 * 
                (r->d + normal * dDotn) * sqrt(1.f + dDotn * dDotn)
                - normal * sqrt(deter));

            if (rRefract->d.x < 0.001 && rRefract->d.x > -0.001 &&
                rRefract->d.y < 0.001 && rRefract->d.y > -0.001 &&
                rRefract->d.z < 0.001 && rRefract->d.z > -0.001) {
                rRefract->d = r->d;
            }
            rRefract->t = FLT_MAX;
            rRefract->point = r->point + (r->t + 0.01f) * r->d;
        
            gRefract = intersectScene(rRefract);
            if (gRefract) {
                clr2 = lightRay(gRefract, rRefract, ref - 1);
            }

            delete rRefract;
        }
    }

    rShadow = new Ray();
    scene->lights.reset();
    while (scene->lights.hasNext()) {
        l = scene->lights.getNext();

        rShadow->point = r->point + r->t * r->d;
        rShadow->d = 
            normalize(l->location - rShadow->point);
        /* prevent self shadowing */
        rShadow->point += normal * 0.01f;
        rShadow->t = FLT_MAX;

        gShadow = intersectScene(rShadow);
        
        if (!gShadow) {
            if (SHADING == 0) {
                clr = shadePhong(g, l, r);
            }
            else if (SHADING == 1) {
                clr = shadeGaussian(g, l, r);
            }
            else if (SHADING == 2) {
                clr = shadeBeckmann(g, l, r);
            }
            else if (SHADING == 3) {
                clr = shadeCookTorrance(g, l, r);
            }

            clr3.r += clr.r;
            clr3.g += clr.g;
            clr3.b += clr.b;
        }
        else if (gShadow->finish.refraction != 0.0) {
            clr3.r += 
                g->pigment.r * g->finish.diffuse * g->finish.ambient * 0.2;
            clr3.g += 
                g->pigment.g * g->finish.diffuse * g->finish.ambient * 0.2;
            clr3.b += 
                g->pigment.b * g->finish.diffuse * g->finish.ambient * 0.2;
        }
    }
    delete rShadow;

    clr.r = clr1.r * fresnel + clr2.r * (1.f - fresnel) + 
        clr3.r * g->pigment.f;
    clr.g = clr1.g * fresnel + clr2.g * (1.f - fresnel) + 
        clr3.g * g->pigment.f;
    clr.b = clr1.b * fresnel + clr2.b * (1.f - fresnel) +
        clr3.b * g->pigment.f;


    clr.r += g->pigment.r * g->finish.ambient;
    clr.g += g->pigment.g * g->finish.ambient;
    clr.b += g->pigment.b * g->finish.ambient;

    return clr;
}

color_t Raytracer::shadePhong(Geometry *g, WLight *l, Ray *r) {
    vec3 normal = normalize(g->getNormal(r));
    vec3 lightDir = normalize(l->location - (r->point + r->t * r->d));
    float NDotL = std::max(0.f, dot(normal, lightDir));
    vec3 R = -lightDir + 2.f * normal * NDotL;
    float VDotR = std::max(0.f, dot(-r->d, R));
    float kspec = 0.0;
    color_t ret;

    if (g->finish.specular && g->finish.roughness) {
        kspec = pow(VDotR, 1.0f/ g->finish.roughness);
    }

    ret.r = 
        (g->pigment.r * g->finish.diffuse) * l->color.x * NDotL +
        (g->pigment.r * g->finish.specular) * l->color.x * kspec;
    ret.g = 
        (g->pigment.g * g->finish.diffuse) * l->color.y * NDotL +
        (g->pigment.g * g->finish.specular) * l->color.y * kspec;
    ret.b = 
        (g->pigment.b * g->finish.diffuse) * l->color.z * NDotL +
        (g->pigment.b * g->finish.specular) * l->color.z * kspec;

    return ret;
}

color_t Raytracer::shadeGaussian(Geometry *g, WLight *l, Ray *r) {
    vec3 normal = normalize(g->getNormal(r));
    vec3 lightDir = normalize(l->location - (r->point + r->t * r->d));
    vec3 H = normalize(lightDir - r->d);
    vec3 R = lightDir - 2.f * dot(normal, lightDir) * normal;
    float NDotL = std::max(0.0f, dot(normal, lightDir));
    float NDotH = std::max(0.0f, dot(normal, H));
    float AngleNH = acos(NDotH);
    float VDotR = std::max(0.0f, dot(-r->d, R));
    float kspec = 0.0;
    color_t ret;
    
    if (g->finish.specular) {
        kspec = exp(-AngleNH * AngleNH /
                    (g->finish.roughness * g->finish.roughness));
    }
 
    ret.r = 
        (g->pigment.r * g->finish.diffuse) * l->color.x * NDotL +
        (g->pigment.r * g->finish.specular) * l->color.x * kspec;
    ret.g = 
        (g->pigment.g * g->finish.diffuse) * l->color.y * NDotL +
        (g->pigment.g * g->finish.specular) * l->color.y * kspec;
    ret.b = 
        (g->pigment.b * g->finish.diffuse) * l->color.z * NDotL +
        (g->pigment.b * g->finish.specular) * l->color.z * kspec;
    ret.f = 1.0;

    return ret;
}

color_t Raytracer::shadeBeckmann(Geometry *g, WLight *l, Ray *r) {
    vec3 normal = normalize(g->getNormal(r));
    vec3 lightDir = normalize(l->location - (r->point + r->t * r->d));
    vec3 H = normalize(lightDir - r->d);
    float NDotL = std::max(0.0f, dot(normal, lightDir));
    float NDotH = std::max(0.0f, dot(normal, H));
    float kspec = 0.0;
    color_t ret;
    
    if (g->finish.specular && NDotH != 0.0f) {
        kspec = exp(-(1.f-NDotH*NDotH) / 
                (g->finish.roughness * g->finish.roughness *
                 NDotH * NDotH)) / (3.1415926f *
                 g->finish.roughness * g->finish.roughness *
                 NDotH * NDotH * NDotH * NDotH);
    }
 
    ret.r = 
        (g->pigment.r * g->finish.diffuse) * l->color.x * NDotL +
        (g->pigment.r * g->finish.specular) * l->color.x * kspec;
    ret.g = 
        (g->pigment.g * g->finish.diffuse) * l->color.y * NDotL +
        (g->pigment.g * g->finish.specular) * l->color.y * kspec;
    ret.b = 
        (g->pigment.b * g->finish.diffuse) * l->color.z * NDotL +
        (g->pigment.b * g->finish.specular) * l->color.z * kspec;
    ret.f = 1.0;

    return ret;
}

color_t Raytracer::shadeCookTorrance(Geometry *g, WLight *l, Ray *r) {
    vec3 normal = normalize(g->getNormal(r));
    vec3 lightDir = normalize(l->location - (r->point + r->t * r->d));
    vec3 H = normalize(lightDir - r->d);
    float NDotL = std::max(0.0f, dot(normal, lightDir));
    float NDotH = std::max(0.0f, dot(normal, H));
    float AngleNH = acos(NDotH);
    float VDotN = std::max(0.0f, dot(normal, -r->d));
    float VDotH = dot(-r->d, H);
    float beckmann = 0.0;
    float fresnel;
    float gatten = 0.0;
    float kspec = 0.0;
    float R0 = (1.f-g->finish.ior)/(1.f+g->finish.ior);
    color_t ret;
    
    if (g->finish.specular && NDotH != 0.0f && VDotN != 0.0 && NDotL != 0.0f) {
        if (g->finish.roughness >= 0.1) {
            beckmann = exp(-(1.f-NDotH*NDotH) / 
                (g->finish.roughness * g->finish.roughness *
                 NDotH * NDotH)) / (3.14159265 *
                 g->finish.roughness * g->finish.roughness *
                 NDotH * NDotH * NDotH * NDotH);
        }
        else {
            /* Use gaussian for shiny materials */
            beckmann = exp(-AngleNH * AngleNH /
                    (g->finish.roughness * g->finish.roughness));
        }

        R0 = R0 * R0;
        fresnel = R0 + (1.f - R0) * 
         (NDotH) * (NDotH) * (NDotH) * (NDotH) * (NDotH);

        gatten = std::min(1.f, std::min(2.f*(NDotH)*(VDotN)/(VDotH),
                2.f * (NDotH) * (NDotL) / (VDotH)));

        kspec = beckmann * fresnel * gatten / (3.141592653 * VDotN * NDotL);
    }
 
    ret.r = 
        (g->pigment.r * g->finish.diffuse) * l->color.x * NDotL +
        (g->pigment.r * g->finish.specular) * l->color.x * kspec;
    ret.g = 
        (g->pigment.g * g->finish.diffuse) * l->color.y * NDotL +
        (g->pigment.g * g->finish.specular) * l->color.y * kspec;
    ret.b = 
        (g->pigment.b * g->finish.diffuse) * l->color.z * NDotL +
        (g->pigment.b * g->finish.specular) * l->color.z * kspec;
    ret.f = 1.0;

    return ret;
}

int main(int argc, char *argv[]) {
    string input, temp, line;
    ifstream file;
    int width, height;
    int argOptions = 0;
    Raytracer *tracer;
    Scene *scene;

    /* make sure our random numbers aren't the same every run */
    srand(time(NULL));

    if (argc < NUMARGS) {
        cout << "Usage: raytrace Width Height -I Filename\n";
        exit(1);
    }

    width = atoi(argv[++argOptions]);
    height = atoi(argv[++argOptions]);

    for (argOptions; argOptions < argc; argOptions++) {
        temp = string(argv[argOptions]);
        if (temp.substr(0, 2).compare("-I") == 0) {
        //get the input file name
            if (temp.length() > 2) {
                temp = temp.substr(2);
            }
            else {
                if (argc < argOptions + 1) {
                    cout << "Usage: raytrace Width Height -I Filename\n";
                    exit(1);
                }
                temp = string(argv[++argOptions]);
            }

            input = temp;
        }
        else if (temp.substr(0, 2).compare("-p") == 0) {
            if (temp.length() > 2) {
                temp = temp.substr(2);
            }
            else {
                if (argc < argOptions + 1) {
                    cout << "Usage: raytrace Width Height -I Filename"
                        " [options]\n";
                    exit(1);
                }

                temp = string(argv[++argOptions]);
            }

            SHADING = strtol(temp.c_str(), NULL, 10);
            if (SHADING > 3) {
                cout << "Cannot find shader " << SHADING << endl;
                exit(1);
            }
        }
        else if (temp.substr(0,2).compare("-r") == 0) {
            if (temp.length() > 2) {
                temp = temp.substr(2);
            }
            else {
                if (argc < argOptions + 1) {
                    cout << "Usage: raytrace Width Height -I Filename"
                        " [options]\n";
                    exit(1);
                }

                temp = string(argv[++argOptions]);
            }

            REFLECT = strtol(temp.c_str(), NULL, 10);
        }
        else if (temp.substr(0, 2).compare("-a") == 0) {
            if (temp.length() > 2) {
                temp = temp.substr(2);
            }
            else {
                if (argc < argOptions + 1) {
                    cout << "Usage: raytrace Width Height -I Filename"
                        " [options]\n";
                    exit(1);
                }

                temp = string(argv[++argOptions]);
            }

            ALIAS = strtol(temp.c_str(), NULL, 10);
        }
    }

    
    if (input.compare("") == 0) {
        cout << "Usage: raytrace Width Height -I Filename\n";
        exit(1);
    }

    if (ALIAS <= 0) {
        ALIAS = 1;
    }

    cout << "Reading the scene\n";
    file.open(input.c_str(), ifstream::in);
    file.unsetf(ios_base::skipws);
    if (file.is_open()) {
        scene = parseScene(file);
    }
    else {
        cout << "Could not open file: " << input << endl;
        exit(1);
    }
    cout << "Read in scene, preparing to trace\n";

    //globalScene.debug();
    tracer = new Raytracer(width, height, 
            string(input.substr(0, input.length() - 4)) + ".tga",
            scene);
    cout << "Tracing\n";
    tracer->trace();
    cout << "finished\n";

    return 0;
}
